#region File Description
//-----------------------------------------------------------------------------
// ModelViewerControl.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using AssetData;
// To avoid ambiguities
using Keys = Microsoft.Xna.Framework.Input.Keys;
using ButtonState = Microsoft.Xna.Framework.Input.ButtonState;
#endregion

namespace Editor
{
    /// <summary>
    /// Example control inherits from GraphicsDeviceControl, and displays
    /// a spinning 3D model. The main form class is responsible for loading
    /// the model: this control just displays it.
    /// </summary>
    public class ModelViewerControl : GraphicsDeviceControl
    {
        private const float cameraInitialAway = 200;
        private const float cameraInitialUp = 100;
        private const float cameraInitialLookUp = 4.0f;

        public ParticleHolder Particles
        {
            get
            {
                return particles;
            }
        }
        private ParticleHolder particles;

        public Model Floor
        {
            get { return floor; }
        }
        private Model floor;
        // Material colours for the floor
        private Vector3 specColourFloor = new Vector3(0.25f);
        private float specPowerFloor = 16f;
        private Vector3 diffColourFloor = Vector3.One;
        public void SetFloorColour(byte R, byte G, byte B)
        {
            diffColourFloor = new Vector3((float)(R / 255f), (float)(G / 255f), (float)(B / 255f));
        }
        public void SetFloorColour(Color colour)
        {
            SetFloorColour(colour.R, colour.G, colour.B);
        }
        public void SetFloorDefaultColour()
        {
            diffColourFloor = Vector3.One;
        }
        private Vector3 emisColourFloor = Vector3.Zero;

        private bool showFloor = true;
        private Vector3 floorCentre = Vector3.Zero;
        private float floorRadius = 10;
        // Scale to make one grid square = 1 unit
        // 100x100 unit grid with 20x20 squares on it
        private float floorScale = 5.0f;
        // Size in units of the grid squares (rounded to the nearest whole number)
        public float GridSquareWidth
        {
            get { return floorScale; }
        }

        private bool showEmitterLocation = false;
        /// <summary>
        /// Displays a dot at the position of the particle emitter.
        /// </summary>
        public bool ShowEmitterLocation
        {
            get { return showEmitterLocation; }
            set { showEmitterLocation = value; }
        }

        /// <summary>
        /// Which way up the camera is
        /// 1 = Y Up (XNA)
        /// 2 = Z Up (Blender)
        /// 3 = Z Down
        /// </summary>
        public int ViewUp
        {
            get { return viewUp; }
            set 
            { 
                viewUp = value;
                InitialiseCameraPosition();
            }
        }
        private int viewUp = 1;

        // Used every frame
        Matrix world = Matrix.Identity;
        Matrix view = Matrix.Identity;
        Matrix projection = Matrix.Identity;
        // Calculated
        float aspectRatio = 1;

        // Camera movement
        KeyboardState currentKeyboardState;
        KeyboardState previousKeyboardState;
        MouseState currentMouseState;
        MouseState previousMouseState;
        // Use to position the cursor each frame while using the mouse
        int mouseX = 0;
        int mouseY = 0;
        int previousMouseX = 0;
        int previousMouseY = 0;
        Vector3 cameraPosition = Vector3.Zero;
        // Point to look at when in orbit mode
        Vector3 orbitCentre = Vector3.Zero;
        // Camera Axes calculated before use
        Vector3 cameraUp = Vector3.Zero;
        Vector3 cameraForward = Vector3.Zero;
        // Movement
        private bool pauseInput = true;
        public bool PauseInput
        {
            get { return pauseInput; }
            set { pauseInput = value; }
        }
        // This is also adjusted by the size of the model based on the floor scale calculation
        private float movePerSec = GlobalSettings.defaultMoveSpeed;
        public float CurrentMoveSpeed
        {
            get { return movePerSec; }
            set { movePerSec = value; }
        }
        private float turnPerSec = GlobalSettings.defaultTurnSpeed;
        public float CurrentTurnSpeed
        {
            get { return turnPerSec; }
            set { turnPerSec = value; }
        }
        private float invertY = 1.0f;
        public bool InvertY
        {
            set
            {
                invertY = 1.0f;
                if (value)
                {
                    invertY = -1.0f;
                }
            }
        }

        // For clearing the screen in the game
        // This is changed to match the control colour
        private Color gameBackColor = Color.CornflowerBlue;

        public void SetBackgroundColour(byte R, byte G, byte B)
        {
            gameBackColor = new Color(R, G, B);
        }
        public void SetBackgroundColour(Color colour)
        {
            gameBackColor = colour;
        }
        /// <summary>
        /// Use whatever the control colour is as the background.
        /// </summary>
        public void SetBackgroundDefault()
        {
            // Get the same background used by the control in a format usable by the game
            gameBackColor = new Color(BackColor.R, BackColor.G, BackColor.B);
        }

        /////////////////////////////////////////////////////////////////////
        // == Colours and Lighting ==
        //
        // Material colours for displaying the models
        private Vector3 specularColour = new Vector3(GlobalSettings.colourSpecularGreyDefault);
        public Vector3 SpecularColour
        {
            get { return specularColour; }
            set { specularColour = value; }
        }

        private float specularPower = 16;
        public float SpecularPower
        {
            get { return specularPower; }
            set { specularPower = value; }
        }

        private Vector3 diffuseColour = Vector3.One;
        public Vector3 DiffuseColour
        {
            get { return diffuseColour; }
            set { diffuseColour = value; }
        }

        private Vector3 emissiveColour = Vector3.Zero;
        public Vector3 EmissiveColour
        {
            get { return emissiveColour; }
            set { emissiveColour = value; }
        }

        private bool light1enabled = true;
        public bool Light1Enabled
        {
            get { return light1enabled; }
            set { light1enabled = value; }
        }

        private bool light2enabled = true;
        public bool Light2Enabled
        {
            get { return light2enabled; }
            set { light2enabled = value; }
        }

        // Key
        private Vector3 light0Reverse = new Vector3(0.5265408f, -0.5735765f, 0.6275069f);
        // Fill
        private Vector3 light1Reverse = new Vector3(-0.7198464f, 0.3420201f, -0.6040227f);
        // Back
        private Vector3 light2Reverse = new Vector3(-0.4545195f, -0.7660444f, -0.4545195f);
        private bool reverseLighting = true;
        public bool ReverseLighting
        {
            get { return reverseLighting; }
            set { reverseLighting = value; }
        }
        //
        /////////////////////////////////////////////////////////////////////


        /// <summary>
        /// For displaying shapes in 3D
        /// </summary>
        private Shapes debugShapes;
        public Shapes DebugShapes
        {
            get { return debugShapes; }
        }

        // To draw axes in the corner of the screen
        private Axes3D axes;
        private bool showAxes = true;
        public bool ShowAxes
        {
            get { return showAxes; }
            set { showAxes = value; }
        }

        private bool wireframeEnabled = false;
        private RasterizerState RasterWireFrame = new RasterizerState();
        private RasterizerState RasterSolid = new RasterizerState();

        //////////////////////////////////////////////////////////////////////
        // == Change ==
        //
        // Pass control back to the form
        public event EventHandler<EventArgs> StepUp;
        public event EventHandler<EventArgs> StepDown;
        public event EventHandler<EventArgs> DeleteBound;
        public event EventHandler<EventArgs> IsMoving;
        public event EventHandler<EventArgs> ChangedOrbit;

        /// <summary>
        /// Load the built inn sample particle effect.
        /// </summary>
        public void InitialiseParticles()
        {
            particles = new ParticleHolder();
            particles.LoadInitialContent(this);
        }


        private bool isOrbit = false;
        public bool OrbitMode
        {
            get { return isOrbit; }
            set 
            {
                if (!isOrbit && value)
                {
                    // Calculate the point we are looking at whenever the mode is enabled
                    float distance = Vector3.Distance(floorCentre, cameraPosition);
                    orbitCentre = cameraPosition + (cameraForward * distance);
                }
                isOrbit = value;
                if (ChangedOrbit != null)
                {
                    ChangedOrbit(this, EventArgs.Empty);
                }
            }
        }

        // Typically -1.0 to + 1.0
        private float autoRotateSpeed = 0;
        public float AutoRotateSpeed
        {
            get { return autoRotateSpeed; }
            set { autoRotateSpeed = value; }
        }

        public void SetFloor(Model aModel)
        {
            if (aModel != null)
            {
                floor = aModel;
                InitialiseCameraPosition();
            }
        }

        public bool ShowFloor(bool enable)
        {
            if (floor != null)
            {
                showFloor = enable;
            }
            else
            {
                showFloor = false;
            }
            return showFloor;
        }

        private void CalculateAxes()
        {
            // Change which way up the model is viewed
            if (viewUp == 3)
            {
                // Z Down
                cameraUp = Vector3.Forward;
                cameraForward = Vector3.Down;
            }
            else if (viewUp == 2)
            {
                // Z Up (Blender default)
                cameraUp = Vector3.Backward;
                cameraForward = Vector3.Up;
            }
            else
            {
                // XNA Default
                cameraUp = Vector3.Up;
                cameraForward = Vector3.Forward;
            }
        }

        public void InitialiseCameraPosition()
        {
            CalculateAxes();
            // Initial viewing location
            float away = cameraInitialAway;
            float up = cameraInitialUp;
            cameraPosition = Vector3.Zero;
            if (floor != null)
            {
                // Still show the floor even if no model has been loaded
                cameraPosition = floorCentre;
                away = floorRadius * 2;
                up = floorRadius;
            }
            // Change which way up the model is viewed
            if (viewUp == 3)
            {
                // Z Down
                cameraPosition.Y -= away;
                cameraPosition.Z += up;
            }
            else if (viewUp == 2)
            {
                // Z Up (Blender default)
                cameraPosition.Y -= away;
                cameraPosition.Z += up;
            }
            else
            {
                // XNA Default
                cameraPosition.Z -= away;
                cameraPosition.Y += up;
            }
            // Stop the orbit
            OrbitMode = false;
            AutoRotateSpeed = 0;
            CalculateProjection();
            InitialiseLookAt();
        }

        // Start looking at the model if present
        private void InitialiseLookAt()
        {
            if (floor != null)
            {
                Vector3 viewPoint = floorCentre;
                if (viewUp == 3)
                {
                    // Z Down
                    viewPoint.Z -= cameraInitialLookUp;
                }
                else if (viewUp == 2)
                {
                    // Z Up (Blender default)
                    viewPoint.Z += cameraInitialLookUp;
                }
                else
                {
                    // XNA Default
                    viewPoint.Y += cameraInitialLookUp;
                }
                cameraForward = viewPoint - cameraPosition;
            }
        }

        private void CalculateProjection()
        {
            // Near is close so we can draw the axes and small models
            float nearClip = 0.05f;
            float farClip = 100;

            if (showFloor && floor != null)
            {
                farClip = floorRadius * 100 * floorScale;
            }
            // Avoids silly values
            farClip = Math.Max(nearClip + 1, farClip);
            projection = Matrix.CreatePerspectiveFieldOfView(1, aspectRatio, nearClip, farClip);
            int x = 0;
            x++;
        }

        public void WireFrameEnable(bool change)
        {
            wireframeEnabled = change;
        }

        public bool IsAxisFontLoaded()
        {
            return axes.FontLoaded;
        }

        public void SetAxisFont(SpriteFont font)
        {
            axes.SetFont(font);
        }
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Particles
        /// <summary>
        /// Setup the particles from the settings loaded from an XML file
        /// or changed from the menus.
        /// Returns any error message.  Returns an empty string if the 
        /// settings are usable without error.
        /// </summary>
        public string ChangeParticles(ParticleSettings pSettings, Texture2D image)
        {
            string result = "";
            particles.SetParticleSettings(pSettings, true);
            particles.SetParticleTexture(image, pSettings.TextureName);
            return result;
        }
        /// <summary>
        /// Setup the particles from the settings loaded from an XML file
        /// or changed from the menus.
        /// Returns any error message.  Returns an empty string if the 
        /// settings are usable without error.
        /// Changing the buffer size will reset the particle.
        /// </summary>
        public string ChangeParticles(ParticleSettings pSettings, bool changeBufferSize)
        {
            string result = "";
            particles.SetParticleSettings(pSettings, changeBufferSize);
            return result;
        }
        /// <summary>
        /// Setup the particles from the settings loaded from an XML file
        /// or changed from the menus.
        /// Returns any error message.  Returns an empty string if the 
        /// settings are usable without error.
        /// </summary>
        public string ChangeParticles(Texture2D image, string fileName)
        {
            string result = "";
            particles.SetParticleTexture(image, fileName);
            return result;
        }

        public string GetTextureName()
        {
            return particles.GetTextureName();
        }

        /// <summary>
        /// Useful when things like save pause everything.
        /// </summary>
        public void RestartParticles()
        {
            particles.Reactivate();
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        //
        #region Game
        /// <summary>
        /// Simulated update called prior to the draw method
        /// </summary>
        protected override void Update(GameTimeMirror gameTime)
        {
            HandleInput(gameTime);

            if (particles != null)
            {
                particles.Update(gameTime);
            }
        }

        // Support English, German and French keyboards
        private void HandleInput(GameTimeMirror gameTime)
        {
            float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds;

            float pitch = 0;
            float turn = 0;
            float speed = 0.0005f * turnPerSec;

            if (pauseInput)
            {
                HandleOrbitOnly(time, speed);
                return;
            }
            // Used to set the dialogue box to prevent the cursor causing problems
            bool isMoving = false;

            currentKeyboardState = Keyboard.GetState();
            currentMouseState = Mouse.GetState();

            // == Rotate ==

            // Mouse look
            // The first time we select the mouse move just position the mouse
            // to a known location otherwise the model will spin dramatically
            if ((currentMouseState.MiddleButton == ButtonState.Pressed &&
                previousMouseState.MiddleButton == ButtonState.Released) ||
                (currentKeyboardState.IsKeyDown(Keys.LeftShift) &&
                previousKeyboardState.IsKeyUp(Keys.LeftShift)) ||
                (currentKeyboardState.IsKeyDown(Keys.RightShift) &&
                previousKeyboardState.IsKeyUp(Keys.RightShift))
                )
            {
                isMoving = true;
                Mouse.WindowHandle = Handle;
                // Save the position of the mouse
                previousMouseX = currentMouseState.X;
                previousMouseY = currentMouseState.Y;
                // Position the cursor a few pixel in from the top left to keep it out of view
                mouseX = GlobalSettings.mouseZeroX;
                mouseY = GlobalSettings.mouseZeroY;
                Mouse.SetPosition(mouseX, mouseY);
            }
            else if (currentKeyboardState.IsKeyDown(Keys.LeftShift) ||
                currentKeyboardState.IsKeyDown(Keys.RightShift) || 
                currentMouseState.MiddleButton == ButtonState.Pressed)
            {
                isMoving = true;
                // Mouse look
                turn = (mouseX - currentMouseState.X) * time * speed;
                pitch = (mouseY - currentMouseState.Y) * time * speed * invertY * -1.0f;
                // centre mouse so we get the change each time
                Mouse.SetPosition(mouseX, mouseY);
            }
            else if ((currentMouseState.MiddleButton == ButtonState.Released &&
                previousMouseState.MiddleButton == ButtonState.Pressed) ||
                (currentKeyboardState.IsKeyUp(Keys.LeftShift) &&
                previousKeyboardState.IsKeyDown(Keys.LeftShift)) ||
                (currentKeyboardState.IsKeyUp(Keys.RightShift) &&
                previousKeyboardState.IsKeyDown(Keys.RightShift))
                )
            {
                // No longer mouse moving so reset the original position
                // This is less likely to cause the mouse to be in the wrong or unexpected position
                Mouse.SetPosition(previousMouseX, previousMouseY);
            }

            // Keyboard look
            if (currentKeyboardState.IsKeyDown(Keys.Up))
            {
                isMoving = true;
                pitch -= time * speed * invertY;
            }

            if (currentKeyboardState.IsKeyDown(Keys.Down))
            {
                isMoving = true;
                pitch += time * speed * invertY;
            }

            if (currentKeyboardState.IsKeyDown(Keys.Left))
            {
                isMoving = true;
                turn += time * speed;
            }

            if (currentKeyboardState.IsKeyDown(Keys.Right))
            {
                isMoving = true;
                turn -= time * speed;
            }

            Vector3 cameraRight = Vector3.Cross(cameraUp, cameraForward);
            Vector3 flatFront = Vector3.Cross(cameraRight, cameraUp);

            Matrix pitchMatrix = Matrix.CreateFromAxisAngle(cameraRight, pitch);
            Matrix turnMatrix = Matrix.CreateFromAxisAngle(cameraUp, turn);

            Vector3 tiltedFront = Vector3.TransformNormal(cameraForward, pitchMatrix * turnMatrix);

            // Check angle so we cant flip over
            if (Vector3.Dot(tiltedFront, flatFront) > 0.001f)
            {
                cameraForward = Vector3.Normalize(tiltedFront);
            }

            cameraForward.Normalize();


            // == Move ==

            if (currentKeyboardState.IsKeyDown(Keys.F))
            {
                isMoving = true;
                // Face the model
                cameraForward = floorCentre - cameraPosition;
                // Keep the turn speed unchanged
            }
            // Orbit mode toggle
            if (currentKeyboardState.IsKeyDown(Keys.O) && previousKeyboardState.IsKeyUp(Keys.O))
            {
                OrbitMode = !isOrbit;
            }

            if (isOrbit)
            {
                isMoving = true;
                cameraForward = orbitCentre - cameraPosition;
                if (!MoreMaths.NearZero(autoRotateSpeed))
                {
                    cameraPosition += cameraRight * time * speed * autoRotateSpeed;
                }
            }
            else
            {
                // Move speed
                speed = 0.005f * movePerSec * floorScale;
            }

            // For the scroll wheel to work the Mouse.WindowHandle must be set to this control
            float scroll = (currentMouseState.ScrollWheelValue - previousMouseState.ScrollWheelValue);
            cameraPosition += cameraForward * time * speed * scroll;

            if (currentKeyboardState.IsKeyDown(Keys.W) || Keyboard.GetState().IsKeyDown(Keys.Z))
            {
                isMoving = true;
                cameraPosition += cameraForward * time * speed;
            }

            if (currentKeyboardState.IsKeyDown(Keys.S))
            {
                isMoving = true;
                cameraPosition -= cameraForward * time * speed;
            }

            if (currentKeyboardState.IsKeyDown(Keys.A) || Keyboard.GetState().IsKeyDown(Keys.Q))
            {
                isMoving = true;
                cameraPosition += cameraRight * time * speed;
            }

            if (currentKeyboardState.IsKeyDown(Keys.D))
            {
                isMoving = true;
                cameraPosition -= cameraRight * time * speed;
            }

            // == Move up and down

            if (currentKeyboardState.IsKeyDown(Keys.PageUp))
            {
                isMoving = true;
                cameraPosition += cameraUp * time * speed;
            }

            if (currentKeyboardState.IsKeyDown(Keys.PageDown))
            {
                isMoving = true;
                cameraPosition -= cameraUp * time * speed;
            }

            // == Other view

            if (currentKeyboardState.IsKeyDown(Keys.R))
            {
                isMoving = true;
                // Reset view
                InitialiseCameraPosition();
            }

            // Create the new view matrix
            view = Matrix.CreateLookAt(cameraPosition, cameraPosition + cameraForward, cameraUp);

            // == Edit Bounds

            if (currentKeyboardState.IsKeyDown(Keys.Space) && 
                previousKeyboardState.IsKeyUp(Keys.Space))
            {
                isMoving = true;
                if (currentKeyboardState.IsKeyDown(Keys.LeftShift) ||
                currentKeyboardState.IsKeyDown(Keys.RightShift))
                {
                    // Use an event to send stuff back to the Main Form
                    if (StepDown != null)
                    {
                        StepDown(this, EventArgs.Empty);
                    }
                }
                else
                {
                    if (StepUp != null)
                    {
                        StepUp(this, EventArgs.Empty);
                    }
                }
            }

            if (currentKeyboardState.IsKeyDown(Keys.Delete) &&
                previousKeyboardState.IsKeyUp(Keys.Delete))
            {
                isMoving = true;
                if (DeleteBound != null)
                {
                    DeleteBound(this, EventArgs.Empty);
                }
            }

            // Set the focus to an unused dialogue to avoid a mess of key input
            if (isMoving)
            {
                if (IsMoving != null)
                {
                    IsMoving(this, EventArgs.Empty);
                }
            }

            previousKeyboardState = currentKeyboardState;
            previousMouseState = currentMouseState;
        }

        private void HandleOrbitOnly(float time, float speed)
        {
            if (!isOrbit || MoreMaths.NearZero(autoRotateSpeed))
            {
                return;
            }
            Vector3 cameraRight = Vector3.Cross(cameraUp, cameraForward);
            cameraForward = orbitCentre - cameraPosition;
            cameraPosition += cameraRight * time * speed * autoRotateSpeed;
            // Create the new view matrix
            view = Matrix.CreateLookAt(cameraPosition, cameraPosition + cameraForward, cameraUp);
            if (IsMoving != null)
            {
                IsMoving(this, EventArgs.Empty);
            }
        }
        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Display
        /// <summary>
        /// Draws the control.
        /// </summary>
        protected override void Draw(GameTimeMirror gameTime)
        {
            GraphicsDevice.Clear(gameBackColor);

            // Set states ready for 3D
            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            if (showFloor && floor != null)
            {
                world = Matrix.CreateTranslation(floorCentre);
                DrawFloor(world, view, projection);
            }

            DrawParticles(gameTime);
            // This may be changed by some particles
            GraphicsDevice.BlendState = BlendState.Opaque;

            DrawStoredShapes();
            DrawEmitterLocation();
            DrawAxes();
        }

        private void DrawParticles(GameTimeMirror gameTime)
        {
            if (particles != null)
            {
                particles.Draw(gameTime, ref view, ref projection);
            }
        }

        private void DrawEmitterLocation()
        {
            if (showEmitterLocation)
            {
                debugShapes.DrawDot(particles.EmitterLocation, Color.Yellow, view, projection);
            }
        }

        private void DrawAxes()
        {
            if (showAxes)
            {
                axes.Draw(cameraPosition, cameraForward, cameraUp, view, projection);
            }
        }

        // Draw shapes regardless of what created them
        private void DrawStoredShapes()
        {
            debugShapes.DrawStoredShapes(view, projection);
        }

        private void DrawRigid(Matrix aWorld, Matrix aView, Matrix aProjection, Model aModel)
        {
            // Draw the model.
            DrawStatic(ref aWorld, ref aView, ref aProjection, aModel, 
                ref specularColour, specularPower, ref diffuseColour, ref emissiveColour);
        }

        private void DrawFloor(Matrix aWorld, Matrix aView, Matrix aProjection)
        {
            // Draw the model.
            DrawStatic(ref aWorld, ref aView, ref aProjection, floor,
                ref specColourFloor, specPowerFloor, ref diffColourFloor, ref emisColourFloor);
        }

        // The floor uses different colours to the loaded model
        private void DrawStatic(ref Matrix aWorld, ref Matrix aView, ref Matrix aProjection, Model aModel, 
            ref Vector3 specColour, float specPower, ref Vector3 diffColour, ref Vector3 emisColour)
        {
            // Draw the model.
            foreach (ModelMesh mesh in aModel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = aWorld;
                    effect.View = aView;
                    effect.Projection = aProjection;

                    effect.EnableDefaultLighting();
                    if (reverseLighting)
                    {
                        effect.DirectionalLight0.Direction = light0Reverse;
                        effect.DirectionalLight1.Direction = light1Reverse;
                        effect.DirectionalLight2.Direction = light2Reverse;
                    }
                    effect.DirectionalLight1.Enabled = light1enabled;
                    effect.DirectionalLight2.Enabled = light2enabled;
                    effect.SpecularColor = specColour;
                    effect.SpecularPower = specPower;
                    effect.DiffuseColor = diffColour;
                    effect.EmissiveColor = emisColour;

                    effect.PreferPerPixelLighting = true;
                }

                mesh.Draw();
            }
        }
        #endregion
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        //
        #region Setup
        /// <summary>
        /// Initializes the control.
        /// </summary>
        protected override void Initialize()
        {
            // Hook the idle event to constantly redraw our animation.
            Application.Idle += delegate { Invalidate(); };

            SetBackgroundDefault();
            aspectRatio = GraphicsDevice.Viewport.AspectRatio;

            // Setup the shapes
            debugShapes = new Shapes(GraphicsDevice);
            axes = new Axes3D(GraphicsDevice);
            axes.CalculateOffsetBasedOn(GraphicsDevice.Viewport.Width);
            System.Diagnostics.Debug.WriteLine("Viewport Width: " + GraphicsDevice.Viewport.Width.ToString());

            RasterWireFrame.CullMode = CullMode.CullCounterClockwiseFace;
            RasterWireFrame.FillMode = FillMode.WireFrame;
            RasterWireFrame.MultiSampleAntiAlias = true;

            RasterSolid.CullMode = CullMode.CullCounterClockwiseFace;
            RasterSolid.FillMode = FillMode.Solid;
            RasterSolid.MultiSampleAntiAlias = true;

            // Initialise mouse and keyboard
            // For the scroll wheel to work the Mouse.WindowHandle must be set to this control
            Mouse.WindowHandle = Handle;
            currentKeyboardState = Keyboard.GetState();
            previousKeyboardState = currentKeyboardState;
            currentMouseState = Mouse.GetState();
            previousMouseState = currentMouseState;
            // A few pixel in from the top left
            // Once the WindowHandlw was set on the mouse this became relative to itself.
            mouseX = GlobalSettings.mouseZeroX;
            mouseY = GlobalSettings.mouseZeroY;
            Mouse.SetPosition(mouseX, mouseY);
        }

        #endregion
        //
        //////////////////////////////////////////////////////////////////////

    }
}
